﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Design.Serialization;
using System.CodeDom;
using System.ComponentModel;
using System.ComponentModel.Design;
using ProgNetUtils;
using System.CodeDom.Compiler;
using System.IO;
using System.Reflection;
using EnvDTE;

namespace ProgNetExtensions.ExtenderProviders.Serialization
{
    class DataSourceProviderSerializer : CodeDomSerializer
    {
        const string ProviderNames = "ProviderNames.cs";
        const string ProviderEditor = "DataProviderNameEditor.cs";

        private void CreateNewClass(IDesignerSerializationManager manager, object value)
        {
           
            DesignerSerializationManager m = manager as DesignerSerializationManager;

            CodeCompileUnit compileUnit = new CodeCompileUnit();
            System.CodeDom.CodeNamespace newNamespace = new System.CodeDom.CodeNamespace("ProgNet.DataProviderNames");
           
            newNamespace.Imports.Add(new CodeNamespaceImport("System"));
           
            CodeTypeDeclaration typeDeclaration = new CodeTypeDeclaration("ProviderNames");
            typeDeclaration.IsClass = true;
            typeDeclaration.IsPartial = true;
            typeDeclaration.Attributes = MemberAttributes.Public | MemberAttributes.Static;
            newNamespace.Types.Add(typeDeclaration);
            if (value is DataProviderTools.DataProviderContainer)
            {
                DataProviderTools.DataProviderContainer container = value as DataProviderTools.DataProviderContainer;
                foreach (DataProviderTools.DataProvider provider in container.Providers)
                {
                    if (!string.IsNullOrEmpty(provider.Name))
                    {
                        CodeMemberField newField = new CodeMemberField(typeof(string), provider.Name.Replace(" ",""));
                        newField.Attributes = MemberAttributes.Public | MemberAttributes.Const;
                        newField.InitExpression = new CodePrimitiveExpression(provider.Name);
                        typeDeclaration.Members.Add(newField);
                    }
                }
            }
            compileUnit.Namespaces.Add(newNamespace);
            string msg = "";
            
            EnvDTE.DTE dte = (DTE) manager.GetService(typeof(DTE));

            msg = dte.ActiveDocument.FullName;
            
            //show(msg);
            if (dte != null)
            {                
                string folder = Path.GetDirectoryName(dte.ActiveDocument.FullName);
                CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp");
                CodeGeneratorOptions options = new CodeGeneratorOptions();
                options.BracingStyle = "C";
                options.BlankLinesBetweenMembers = false;
                
                StreamWriter sourceWriter = new StreamWriter(folder + "\\" + ProviderNames);
                
                codeProvider.GenerateCodeFromCompileUnit(compileUnit, sourceWriter, options);
                sourceWriter.Flush();
                sourceWriter.Close();
                
                ProjectItem proj = (ProjectItem)manager.GetService(typeof(ProjectItem));
                proj.ContainingProject.ProjectItems.AddFromFile(folder + "\\" + ProviderNames);
                //if (proj != null)
                //{
                //    //show("proj != null");
                //    ProjectItem item = proj.ProjectItems.AddFromFile(folder + "\\" + ProviderNames);
                //}
                //sourceWriter = new StreamWriter(folder + "\\" + ProviderNames);
                
                //codeProvider.GenerateCodeFromCompileUnit(compileUnit, sourceWriter, options);
                //sourceWriter.Flush();
                //sourceWriter.Close();
                
            }
            
        }
        private void CreateNewClass2(IDesignerSerializationManager manager, object value)
        {

            DesignerSerializationManager m = manager as DesignerSerializationManager;

            CodeCompileUnit compileUnit = new CodeCompileUnit();
            System.CodeDom.CodeNamespace newNamespace = new System.CodeDom.CodeNamespace("ProgNetExtensions.Editors");

            newNamespace.Imports.Add(new CodeNamespaceImport("System"));
            newNamespace.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
            newNamespace.Imports.Add(new CodeNamespaceImport("System.Drawing.Design"));
            newNamespace.Imports.Add(new CodeNamespaceImport("System.Windows.Forms.Design"));
            newNamespace.Imports.Add(new CodeNamespaceImport("System.Windows.Forms"));
            newNamespace.Imports.Add(new CodeNamespaceImport("System.Reflection"));


            CodeTypeDeclaration typeDeclaration = new CodeTypeDeclaration("DataProviderNameEditor");
            typeDeclaration.BaseTypes.Add("UITypeEditor");
            typeDeclaration.IsClass = true;
            typeDeclaration.IsPartial = false;
            typeDeclaration.Attributes = MemberAttributes.Public;
            newNamespace.Types.Add(typeDeclaration);

            CodeMemberMethod met = new CodeMemberMethod();
            met.Attributes = MemberAttributes.Override | MemberAttributes.Public;
            met.Name = "GetEditStyle";
            met.ReturnType = new CodeTypeReference("UITypeEditorEditStyle");
            met.Parameters.Add(new CodeParameterDeclarationExpression("System.ComponentModel.ITypeDescriptorContext", "context"));
            met.Statements.Add(new CodeSnippetExpression("return UITypeEditorEditStyle.DropDown"));


            typeDeclaration.Members.Add(met);
            met = new CodeMemberMethod();




            met.Name = "EditValue";
            met.Parameters.Add(new CodeParameterDeclarationExpression("System.ComponentModel.ITypeDescriptorContext", "context"));
            met.Parameters.Add(new CodeParameterDeclarationExpression("IServiceProvider", "provider"));
            met.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "value"));
            met.Attributes = MemberAttributes.Public | MemberAttributes.Override;
            met.ReturnType = new CodeTypeReference(typeof(object));
            met.Statements.Add(new CodeSnippetExpression("IWindowsFormsEditorService srv = (IWindowsFormsEditorService)context.GetService(typeof(IWindowsFormsEditorService))"));
            met.Statements.Add(new CodeSnippetExpression("ListBox cb = new ListBox()"));
            met.Statements.Add(new CodeSnippetExpression("Type t = typeof(ProgNet.DataProviderNames.ProviderNames)"));
            met.Statements.Add(new CodeSnippetExpression("FieldInfo[] fis = t.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy)"));
            string indexName = "index";
            string fisName = "fis";
            CodeVariableDeclarationStatement index =
               new CodeVariableDeclarationStatement(typeof(int), indexName, new CodePrimitiveExpression(0));

            CodePropertyReferenceExpression fisLength =
               new CodePropertyReferenceExpression(
                   new CodeVariableReferenceExpression(fisName),
                   "Length");



            CodeBinaryOperatorExpression indexLTLength = new CodeBinaryOperatorExpression(
               new CodeVariableReferenceExpression(indexName),
               CodeBinaryOperatorType.LessThan,
               fisLength);

            CodeAssignStatement indexIncrement = new CodeAssignStatement(
               new CodeVariableReferenceExpression(indexName),
               new CodeBinaryOperatorExpression(
                   new CodeVariableReferenceExpression(indexName),
                   CodeBinaryOperatorType.Add,
                   new CodePrimitiveExpression(1)
                   ));


            CodeArrayIndexerExpression fisAtIndex = new CodeArrayIndexerExpression(
               new CodeVariableReferenceExpression(fisName),
               new CodeExpression[] {
                   new CodeVariableReferenceExpression(indexName)
               }
               );
            CodePropertyReferenceExpression fiName = new CodePropertyReferenceExpression(fisAtIndex, "Name");
            

            CodeVariableReferenceExpression listBox = new CodeVariableReferenceExpression("cb");
            CodePropertyReferenceExpression listBoxItems = new CodePropertyReferenceExpression(listBox, "Items");

            CodeMethodReferenceExpression AddItem = new CodeMethodReferenceExpression(listBoxItems, "Add");



            CodeMethodInvokeExpression performAdd =
                new CodeMethodInvokeExpression(AddItem, new CodeExpression[] { fiName });

            CodeStatement[] loopBody =
                new CodeStatement[] { new CodeExpressionStatement(performAdd) };

            CodeIterationStatement forColors = new CodeIterationStatement(index,
                indexLTLength,
                indexIncrement,
                loopBody);
            met.Statements.Add(forColors);
            met.Statements.Add(new CodeSnippetExpression("cb.Dock = DockStyle.Fill"));
            met.Statements.Add(new CodeSnippetExpression("cb.Dock = DockStyle.Fill"));
            met.Statements.Add(new CodeSnippetExpression("cb.Click += new EventHandler(cb_Click)"));
            met.Statements.Add(new CodeSnippetExpression("srv.DropDownControl(cb)"));
            met.Statements.Add(new CodeSnippetExpression("return base.EditValue(context, provider, value)"));
            typeDeclaration.Members.Add(met);

            met = new CodeMemberMethod();
            met.Name = "cb_Click";
            met.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "sender"));
            met.Parameters.Add(new CodeParameterDeclarationExpression(typeof(EventArgs), "e"));

            compileUnit.Namespaces.Add(newNamespace);
            string msg = "";

            EnvDTE.DTE dte = (DTE)manager.GetService(typeof(DTE));

            msg = dte.ActiveDocument.FullName;

            //show(msg);
            if (dte != null)
            {
                string folder = Path.GetDirectoryName(dte.ActiveDocument.FullName);
                CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp");
                CodeGeneratorOptions options = new CodeGeneratorOptions();
                options.BracingStyle = "C";
                options.BlankLinesBetweenMembers = false;

                StreamWriter sourceWriter = new StreamWriter(folder + "\\" + ProviderEditor);

                codeProvider.GenerateCodeFromCompileUnit(compileUnit, sourceWriter, options);
                sourceWriter.Flush();
                sourceWriter.Close();

                ProjectItem proj = (ProjectItem)manager.GetService(typeof(ProjectItem));
                proj.ContainingProject.ProjectItems.AddFromFile(folder + "\\" + ProviderEditor);
                

            }

        }
        
        public override object Serialize(IDesignerSerializationManager manager, object value)
        {
            object codeObject = null;
            
            CodeDomSerializer serializer = (CodeDomSerializer)manager.GetSerializer(typeof(DataSourceProvider), typeof(CodeDomSerializer));
            if (serializer != null)
                codeObject = serializer.Serialize(manager, value);
            //show("name = " + value.GetType().Module.Assembly.Location);
            try
            {
                string msg = "";
                CodeStatementCollection statements = codeObject as CodeStatementCollection;
                int i = 0;
                foreach (CodeStatement s in statements)
                {
                    msg += i + " - " + (s.LinePragma != null);
                }
                //show(msg);

                
                CreateNewClass(manager, value);
                CreateNewClass2(manager, value);
            }
            catch (Exception ex)
            {
                show(ex.Message);
            }
            return codeObject;
        }

        private void show(string msg)
        {
            System.Windows.Forms.MessageBox.Show(msg);
        }
    }
    
}